#include "ClientInfo.h"
#include <sstream>
#include <stdexcept>
#include <iostream>

constexpr uint8_t ClientInfo::PARAM_TYPE_SIZE;
constexpr uint8_t ClientInfo::PARAM_LENGTH_SIZE;
constexpr uint8_t ClientInfo::BUFFER_INFO_SIZE;
constexpr uint8_t ClientInfo::PROTOCOL_VERSION_SIZE;
constexpr uint8_t ClientInfo::PROTOCOL_VERSION_INTERNAL_SIZE;
constexpr uint8_t ClientInfo::COMMAND_TIMEOUT_SIZE;
constexpr uint8_t ClientInfo::INTER_TRANSACTION_DELAY_SIZE;
constexpr float ClientInfo::SECONDS_PER_LSB;
constexpr uint8_t ClientInfo::LSBS_PER_SECOND;

// 构造函数实现
ClientInfo::ClientInfo(uint8_t major, uint8_t minor, uint8_t patch, uint8_t alpha, bool alphaValid, uint8_t bufferCount, uint16_t bufferSize,
                       float defaultTimeout, const std::map<MdfuCmd, float> &timeouts, float interTransactionDelay)
    : protocolMajor(major), protocolMinor(minor), protocolPatch(patch), protocolAlpha(alpha), protocolAlphaValid(alphaValid), bufferCount(bufferCount),
      bufferSize(bufferSize), defaultTimeout(defaultTimeout), timeouts(timeouts), interTransactionDelay(interTransactionDelay) {}

// 转换为字节流
std::vector<uint8_t> ClientInfo::toBytes() const
{
    std::vector<uint8_t> data;

    // 添加 BUFFER_INFO
    data.push_back(static_cast<uint8_t>(ClientInfoType::BUFFER_INFO));
    data.push_back(BUFFER_INFO_SIZE);
    data.push_back(static_cast<uint8_t>(bufferSize & 0xFF));
    data.push_back(static_cast<uint8_t>((bufferSize >> 8) & 0xFF));
    data.push_back(bufferCount);

    // 添加 PROTOCOL_VERSION
    data.push_back(static_cast<uint8_t>(ClientInfoType::PROTOCOL_VERSION));
    data.push_back(PROTOCOL_VERSION_SIZE);
    data.push_back(protocolMajor);
    data.push_back(protocolMinor);
    data.push_back(protocolPatch);

    // 添加 COMMAND_TIMEOUTS
    data.push_back(static_cast<uint8_t>(ClientInfoType::COMMAND_TIMEOUTS));
    uint8_t timeoutsSize = static_cast<uint8_t>((timeouts.size() + 1) * COMMAND_TIMEOUT_SIZE);
    data.push_back(timeoutsSize);
    data.push_back(0);
    uint16_t defaultTimeoutVal = static_cast<uint16_t>(defaultTimeout * LSBS_PER_SECOND);
    data.push_back(static_cast<uint8_t>(defaultTimeoutVal & 0xFF));
    data.push_back(static_cast<uint8_t>((defaultTimeoutVal >> 8) & 0xFF));
    for (const auto &[cmd, timeout] : timeouts)
    {
        data.push_back(static_cast<uint8_t>(cmd));
        uint16_t timeoutVal = static_cast<uint16_t>(timeout * LSBS_PER_SECOND);
        data.push_back(static_cast<uint8_t>(timeoutVal & 0xFF));
        data.push_back(static_cast<uint8_t>((timeoutVal >> 8) & 0xFF));
    }

    // 添加 INTER_TRANSACTION_DELAY
    if (interTransactionDelay > 0)
    {
        data.push_back(static_cast<uint8_t>(ClientInfoType::INTER_TRANSACTION_DELAY));
        data.push_back(INTER_TRANSACTION_DELAY_SIZE);
        uint32_t itdVal = static_cast<uint32_t>(interTransactionDelay * LSBS_PER_SECOND);
        data.push_back(static_cast<uint8_t>(itdVal & 0xFF));
        data.push_back(static_cast<uint8_t>((itdVal >> 8) & 0xFF));
        data.push_back(static_cast<uint8_t>((itdVal >> 16) & 0xFF));
        data.push_back(static_cast<uint8_t>((itdVal >> 24) & 0xFF));
    }
    return data;
}

// 从字节流解析 ClientInfo
ClientInfo ClientInfo::fromBytes(const std::vector<uint8_t> &data)
{
    size_t i = 0;
    uint8_t major = 0, minor = 0, patch = 0, alpha = 0, bufferCount = 0;
    bool alphaValid = false;
    uint16_t bufferSize = 0;
    float defaultTimeout = 0.0f;
    std::map<MdfuCmd, float> timeouts;
    float interTransactionDelay = 0.0f;

    // TODO 测试命令校验正确性
    while (i < data.size())
    {
        ClientInfoType type = static_cast<ClientInfoType>(data[i]);
        uint8_t length = data[i + 1];
        std::vector<uint8_t> value(data.begin() + i + 2, data.begin() + i + 2 + length);

        switch (type)
        {
        case ClientInfoType::BUFFER_INFO:
            bufferSize = value[0] | (value[1] << 8);
            bufferCount = value[2];
            break;
        case ClientInfoType::PROTOCOL_VERSION:
            major = value[0];
            minor = value[1];
            patch = value[2];
            if (length == PROTOCOL_VERSION_INTERNAL_SIZE)
            {
                alpha = value[3];
                alphaValid = true;
            }
            break;
        case ClientInfoType::COMMAND_TIMEOUTS:
            defaultTimeout = static_cast<float>(value[1] | (value[2] << 8)) * SECONDS_PER_LSB;
            for (size_t j = 3; j < length; j += 3)
            {
                MdfuCmd cmd = static_cast<MdfuCmd>(value[j]);
                float timeout = static_cast<float>(value[j + 1] | (value[j + 2] << 8)) * SECONDS_PER_LSB;
                timeouts[cmd] = timeout;
            }
            break;
        case ClientInfoType::INTER_TRANSACTION_DELAY:
            interTransactionDelay = static_cast<float>(value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24)) * SECONDS_PER_LSB;
            break;
        default:
            throw std::runtime_error("Unknown ClientInfoType encountered");
        }
        i += 2 + length;
    }

    return ClientInfo(major, minor, patch, alpha, alphaValid, bufferCount, bufferSize, defaultTimeout, timeouts, interTransactionDelay);
}

// 获取 MDFU 版本
std::string ClientInfo::getProtocolVersion() const
{
    if (protocolAlphaValid)
    {
        return std::to_string(protocolMajor) + "." + std::to_string(protocolMinor) + "." + std::to_string(protocolPatch) + "-alpha" + std::to_string(protocolAlpha);
    }
    return std::to_string(protocolMajor) + "." + std::to_string(protocolMinor) + "." + std::to_string(protocolPatch);
}

// 获取缓冲区信息
uint16_t ClientInfo::getBufferSize() const { return bufferSize; }
uint8_t ClientInfo::getBufferCount() const { return bufferCount; }

// 获取超时时间
float ClientInfo::getDefaultTimeout() const { return defaultTimeout; }
float ClientInfo::getCommandTimeout(MdfuCmd cmd) const
{
    if (timeouts.find(cmd) != timeouts.end())
    {
        return timeouts.at(cmd);
    }
    return defaultTimeout;
}

// 获取事务间延迟
float ClientInfo::getInterTransactionDelay() const { return interTransactionDelay; }
